package com.jt;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sun.security.jca.ServiceId;

import java.net.URI;
import java.util.Random;

@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
    /*创建RestTemplate对象,然后基于此对象进行远程服务调用
    * @Bean 注解用于描述方法,用于告诉spring框架这个方法的返回值交给spring管理,
    * spring默认会给这个方法返回对象起一个bean的名字(key),默认为方法名.
    * 当然也可以对一个bean的名字进行自定义,例如@Bean("自己定义的名字").
    * 思考: spring框架中为什么会给出这样的注解,用于描述方法,在方法中构建对象?
    * ①:Spring是一个资源整合框架.
    * ②:何为资源?(内存中对象)
    *
    * */
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Bean
    @LoadBalanced //这个注解描述RestTemplate对象时,系统底层会对RestTemplate对象的请求进行拦截
    public RestTemplate loadBalancerrestTemplate(){
        return new RestTemplate();
    }

    @Value("${spring.application.name}")
    private String appName;
    @RestController
    public class ConsumerController{
        @Autowired
        private RestTemplate restTemplate;

        /**
         * @Autowired注解描述属性时,会告诉spring框架,要优先按属性类型进行对象的查找和注入,假如
         * 此类型的对象存在多个,此时还会按照属性名进行查找和比对,有相同的则直接注入(DI),没有相同的
         * 则出错,当然也可以在属性上添加@Qualifier("bean的名字")注解,指定要注入的具体对象
         * */
        @Autowired
        private RestTemplate loadBalancerrestTemplate;
        //负载均衡客户端对象(基于此对象可以从nacos中获取服务列表,并且可以基于一定的算法)
        //从列表中获取一个服务实例
        @Autowired
        private LoadBalancerClient loadBalancerClient;

        //负载均衡方式的调用1
        @GetMapping("/consumer/echo")
        public String doRestEcho1(){
            //基于loadBalancerClient方式获取服务实例
            String serviceId = "sca-provider";//这个名字要在nacos的服务列表中
            ServiceInstance choose = loadBalancerClient.choose(serviceId);
            String ip = choose.getHost();
            int port = choose.getPort();
            //String url = "http://"+ip+":"+port+"/provider/echo"+appName;
            String url = String.format("http://%s:%s/provider/echo/%s",ip,port,appName);
            return restTemplate.getForObject(url,String.class);
        }

        //负载均衡应用方式2:@LoadBalanced
        @GetMapping("/consumer/echo2")
        public String doRestEcho2(){
            String serviceId = "sca-provider";
            String url = String.format("http://%s/provider/echo/%s",serviceId,appName);
            //底层在基于loadBalancerrestTemplate对象访问方式,会启动一个拦截器
            return loadBalancerrestTemplate.getForObject(url,String.class);


        }
    }
}
